#include "utilities.h"

void joinProcessing(msg_header msgRespHdr, listBuffStruct eventReq)
{
	map<int,writeListData>::iterator it;
	list<fromUOIDStr>::iterator itF;
	struct timeval readtime;
	//Process the Join request accordingly
	if((uint8_t)msgRespHdr.msgtype == JNRQ)
	{
		
		join_msg tempJoinMsg;
		memcpy(&(tempJoinMsg.hostlocation), &(eventReq.listBuff[27]), sizeof(uint32_t));
		memcpy(&(tempJoinMsg.hostport), &(eventReq.listBuff[31]), sizeof(uint16_t));
		memset(tempJoinMsg.hostname, '\0', 512);
		memcpy(&(tempJoinMsg.hostname), &(eventReq.listBuff[33]), (msgRespHdr.datalength-sizeof(uint32_t)-sizeof(uint16_t)));
		if(printFlag==1)
		{
			cout<<"Got Join Request msg from - "<<eventReq.portNumber<<endl;
		}
		//Find the UOID in the uoid queue and remove if duplicate i.e. if testUOID = 1
		int testUOID = findInUOIDList(msgRespHdr.uoid);
		if(testUOID == 1)
		{
			
		}
		else
		{
			//Put the UOID in uoid queue
			uoidStr tempUOIDStr;
			struct timeval time1;
			gettimeofday(&time1, NULL);
			tempUOIDStr.timeOfTheDay = (double)(time1.tv_sec * (1e+3) + (double)time1.tv_usec/1000);
			tempUOIDStr.msgLifeTime = initMap["MsgLifetime"];
			memcpy(tempUOIDStr.msgUOID, msgRespHdr.uoid, 20);
			pthread_mutex_lock(&uoidlock);
			myUOIDList.push_back(tempUOIDStr);
			pthread_mutex_unlock(&uoidlock);
			//if TTL is 1 then do not forward
			if(msgRespHdr.timetolive==1)
			{
				
			}
			else
			{
				//Forward the request to neighbors and reduce TTL by 1
				listBuffStruct lbtemp;
				lbtemp.logtype=2;
				int tempTTL = msgRespHdr.timetolive;
				tempTTL--;
				msgRespHdr.timetolive = tempTTL;
				memset(&lbtemp.listBuff, '\0', 8192);
				fillMsgHdrBuffer(msgRespHdr, lbtemp.listBuff);
				memcpy(&(lbtemp.listBuff[27]),&(tempJoinMsg.hostlocation), sizeof(uint32_t));
				memcpy(&(lbtemp.listBuff[31]),&(tempJoinMsg.hostport), sizeof(uint16_t));
				memcpy(&(lbtemp.listBuff[33]),&(tempJoinMsg.hostname), (msgRespHdr.datalength-sizeof(uint32_t)-sizeof(uint16_t)));
				lbtemp.datalength = 27 + msgRespHdr.datalength;
				pthread_mutex_lock(&writeMapMutex);
				for(it=writeMap.begin(); it!=writeMap.end(); it++)
				{
					if((*it).first!=eventReq.portNumber)
					{
						//store the uoid in a map so that when it recieves a response then send it to the persone who initiated it.
						fromUOIDStr fromTemp;
						memcpy(fromTemp.uoid, &msgRespHdr.uoid, 20);
						fromTemp.portnumber = eventReq.portNumber;
						myFromUOIDList.push_back(fromTemp);
						lbtemp.portNumber = (*it).first;
						writeListData listDataStr = writeMap[(*it).first];
						listDataStr.response.push_back(lbtemp);
						writeMap[(*it).first] = listDataStr;
					}
				}
				pthread_mutex_unlock(&writeMapMutex);
			}
			//Make the Response and put in write queue
			//1. Make status response
			uint32_t distance = 0;
			int dataLen = 0;
			join_response_msg joinRspMsg;
			memcpy(&(joinRspMsg.uoid), &msgRespHdr.uoid, 20);
			memset(&(joinRspMsg.hostname), '\0', 512);
			memcpy(&(joinRspMsg.hostname), hostname, strlen(hostname));
			joinRspMsg.hostport = port_recieve;
			//Calculate the distance and store it in the structure
			int joinDistance = (int)tempJoinMsg.hostlocation;
			int di = abs(joinDistance - (int)initMap["Location"].asDouble);
			distance = di;
			if(printFlag==1)
			{
				cout<<distance<<" - Dist"<<endl;
			}
			memcpy(&(joinRspMsg.distance), &distance, sizeof(uint32_t));
			dataLen = 20+sizeof(uint32_t)+sizeof(uint16_t)+strlen(joinRspMsg.hostname);
			//2. Make header
			char obj[512];
			msg_header responseHdr;
			strcpy(obj,"STRS");
			createMsgHdrStr(&responseHdr,0xFB,initMap["TTL"].asDouble,obj,node_instance_id, dataLen);
			//copy the above structures into message response structure
			listBuffStruct lbtemp;
			lbtemp.logtype=1;
			memset(&lbtemp.listBuff, '\0', 8192);
			fillMsgHdrBuffer(responseHdr, lbtemp.listBuff);

			memcpy(&(lbtemp.listBuff[27]),&(joinRspMsg.uoid),20);
			memcpy(&(lbtemp.listBuff[47]),&(joinRspMsg.distance),sizeof(uint32_t));
			memcpy(&(lbtemp.listBuff[51]),&(joinRspMsg.hostport),sizeof(uint16_t));
			memcpy(&(lbtemp.listBuff[53]),joinRspMsg.hostname,strlen(joinRspMsg.hostname));
			lbtemp.datalength = 27+dataLen;
			lbtemp.portNumber = eventReq.portNumber;
			if(joinRequestMap[eventReq.portNumber]==true)
			{
				beaconmap temp1;
				pthread_mutex_lock(&maplock);
				temp1.socknumber = myMap[eventReq.portNumber].socknumber;
				pthread_mutex_unlock(&maplock);
				write(temp1.socknumber,lbtemp.listBuff,lbtemp.datalength);
				gettimeofday(&readtime,NULL);
				write_to_log(lbtemp,1,readtime);
			}
			else
			{
				pthread_mutex_lock(&writeMapMutex);
				writeListData listDataStr = writeMap[eventReq.portNumber];
				//put them in the writeQueue.
				listDataStr.response.push_back(lbtemp);
				writeMap[eventReq.portNumber] = listDataStr;
				pthread_mutex_unlock(&writeMapMutex);
			}
		}
	}
	
	//Process the Join response accordingly
	if((uint8_t)msgRespHdr.msgtype == JNRS)
	{
		if(printFlag==1)
		{
			cout<<"Got Join Response msg from - "<<eventReq.portNumber<<endl;
		}
		join_response_msg tempJoinMsg;
		memcpy(&(tempJoinMsg.uoid), &(eventReq.listBuff[27]), 20);
		memcpy(&(tempJoinMsg.distance), &(eventReq.listBuff[47]), sizeof(uint32_t));
		memcpy(&(tempJoinMsg.hostport), &(eventReq.listBuff[51]), sizeof(uint16_t));
		memset(tempJoinMsg.hostname, '\0', 512);
		memcpy(&(tempJoinMsg.hostname), &(eventReq.listBuff[53]), (msgRespHdr.datalength-(20+sizeof(uint32_t)+sizeof(uint16_t))));
		//If I am not the request initiator then send it to the person who requested/forwarded the request
		int testUOID = findInUOIDList(msgRespHdr.uoid);
		if(printFlag==1)
		{
			cout<<"Sigged"<<endl;
		}
		if(testUOID == 1)
		{
			
		}
		else
		{
			//Store the request in the uoid queue.
			uoidStr tempUOIDStr;
			struct timeval time1;
			gettimeofday(&time1, NULL);
			tempUOIDStr.timeOfTheDay = (double)(time1.tv_sec * (1e+3) + (double)time1.tv_usec/1000);
			tempUOIDStr.msgLifeTime = initMap["MsgLifetime"];
			memcpy(tempUOIDStr.msgUOID, msgRespHdr.uoid, 20);
			pthread_mutex_lock(&uoidlock);
			myUOIDList.push_back(tempUOIDStr);
			pthread_mutex_unlock(&uoidlock);
			//If TTL is 1 then do not forward
			if(msgRespHdr.timetolive==1)
			{
		
			}
			else
			{
				//Sending the response to the forwarder
				char *uoid = new char[20];
				memcpy(&uoid, &tempJoinMsg.uoid, 20);
				
				listBuffStruct lbtemp;
				int tempTTL = msgRespHdr.timetolive;
				tempTTL--;
				msgRespHdr.timetolive = tempTTL;
				memset(&lbtemp.listBuff, '\0', 8192);
				fillMsgHdrBuffer(msgRespHdr, lbtemp.listBuff);
				memcpy(&(lbtemp.listBuff[27]),&(tempJoinMsg.uoid),20);
				memcpy(&(lbtemp.listBuff[47]),&(tempJoinMsg.distance),sizeof(uint32_t));
				memcpy(&(lbtemp.listBuff[51]),&(tempJoinMsg.hostport),sizeof(uint16_t));
				memcpy(&(lbtemp.listBuff[53]),&(tempJoinMsg.hostname), strlen(tempJoinMsg.hostname));
				lbtemp.datalength = eventReq.datalength;
				lbtemp.portNumber = eventReq.portNumber;
				lbtemp.logtype=2;
				bool tempflag = false;
				fromUOIDStr fromTemp;
				for(itF=myFromUOIDList.begin(); itF!=myFromUOIDList.end(); itF++)
				{
					fromTemp = *itF;
					if(printFlag==1)
					{
						cout<<"flag "<<fromTemp.portnumber<<endl;
					}
					if(memcmp(tempJoinMsg.uoid,fromTemp.uoid,20)!=0)
					{
						continue;
					}
					if(joinRequestMap[fromTemp.portnumber] == true)
					{
						tempflag=true;
						beaconmap temp1;
						pthread_mutex_lock(&maplock);
						temp1.socknumber = myMap[fromTemp.portnumber].socknumber;
						pthread_mutex_unlock(&maplock);
						gettimeofday(&readtime,NULL);
						write(temp1.socknumber,lbtemp.listBuff,lbtemp.datalength);
						if(joinFlag==true)
						{
							joinRequestMap[fromTemp.portnumber] = false;
							joinFlag = false;
						}
						else
						{
							lbtemp.portNumber = fromTemp.portnumber;
							write_to_log(lbtemp,1,readtime);
							break;
						}
					}
				}
				if(tempflag == true)
				{
					
				}
				else
				{
					pthread_mutex_lock(&writeMapMutex);
					for(itF=myFromUOIDList.begin(); itF!=myFromUOIDList.end(); itF++)
					{
						fromUOIDStr temp = *itF;
						if(printFlag==1)
						{
						cout<<"sigging"<<endl;
						}
						if(memcmp(tempJoinMsg.uoid,temp.uoid,20)==0)
						{
							writeListData listDataStr = writeMap[temp.portnumber];
							listDataStr.response.push_back(lbtemp);
							writeMap[temp.portnumber] = listDataStr;
							break;
						}
					}
					if(printFlag==1)
					{
						cout<<"fin sigging"<<endl;
					}
					pthread_mutex_unlock(&writeMapMutex);
				}
			}
		}
	}
}
